home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc Development Framework / ODFDev / ODF / Found / FWStream / Sources / FWArDyna.cpp next >
Encoding:
Text File  |  1996-04-25  |  18.0 KB  |  519 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWArDyna.cpp
  4. //    Release Version:    $ ODF 1 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWFound.hpp"
  11.  
  12. #ifndef FWEXCEPT_H
  13. #include "FWExcept.h"
  14. #endif
  15.  
  16. #ifndef FWARDYNA_H
  17. #include "FWArDyna.h"
  18. #endif
  19.  
  20. #ifndef FWPRISTR_H
  21. #include "FWPriStr.h"
  22. #endif
  23.  
  24. #ifndef FWPRIDEB_H
  25. #include "FWPriDeb.h"
  26. #endif
  27.  
  28. #ifndef FWARCOBJ_K
  29. #include "FWArcObj.k"
  30. #endif
  31.  
  32. #ifdef FW_DEBUG
  33. #include <stdio.h>
  34. #endif
  35.  
  36. #include "FWTMap.tpp"
  37.  
  38. #ifdef FW_BUILD_MAC
  39. #pragma segment FWArchiv
  40. #endif
  41.  
  42. #if defined(__MWERKS__) && GENERATING68K
  43. // A hack to work around a bug
  44. #pragma import list somExceptionId,somExceptionValue,somSetException,somExceptionFree
  45. #if defined(FW_ODFLIB_IMPORT)
  46. #pragma import list FW_OObjectRegistryClassData
  47. #endif
  48. #endif
  49.  
  50. //========================================================================================
  51. //    Constants having file scope
  52. //========================================================================================
  53.  
  54. const short kIDOnly = FW_kPrivIDOnly;
  55. const short kIDAndValue = FW_kPrivIDAndValue;
  56.  
  57. const FW_ObjectRegistry_ID kNotInRegistry = FW_kPrivNotInRegistry;
  58. const FW_ObjectRegistry_ID kNULLObjectID = FW_kPrivNULLObjectID;
  59.  
  60. //========================================================================================
  61. //    Keys Matching Function
  62. //========================================================================================
  63.  
  64. static int FW_PrivCompareNames(void* first, void* second);
  65. static int FW_PrivCompareLabels(void* first, void* second);
  66.  
  67. //========================================================================================
  68. //    Template Instantiations
  69. //========================================================================================
  70.  
  71. #ifdef FW_USE_TEMPLATE_PRAGMAS
  72.  
  73. #pragma template_access public
  74. #pragma template FW_TMap<FW_SPrivArcStr, FW_ClassTypeConstant>
  75. #pragma template FW_TMap<FW_ClassTypeConstant, FW_SPrivArcFun>
  76.  
  77. #else
  78.  
  79. template class FW_TMap<FW_SPrivArcStr, FW_ClassTypeConstant>;
  80. template class FW_TMap<FW_ClassTypeConstant, FW_SPrivArcFun>;
  81.  
  82. #endif
  83.  
  84. static void* ClassLabel_Create(FW_CReadableStream& stream, FW_ClassTypeConstant type);
  85. static void ClassLabel_Output(FW_CWritableStream& stream, FW_ClassTypeConstant type, const void *object);
  86.  
  87. FW_ClassTypeConstant kMetaClassTypeConstant = FW_TYPE_CONSTANT('c', 'l', 'a', 's');
  88. FW_CPrivArchiver gFWArchiveMetaClass(kMetaClassTypeConstant, FW_SPrivArcFun(ClassLabel_Create, 0, 0, ClassLabel_Output));
  89.  
  90. //========================================================================================
  91. //    Class FW_CPrivArchiver
  92. //========================================================================================
  93.  
  94. FW_SPrivArchiverGlobals FW_CPrivArchiver::gGlobals;
  95.  
  96. //----------------------------------------------------------------------------------------
  97. // FW_CArchiveDictionary& FW_CPrivArchiver::GetNameToLabelMap
  98. //----------------------------------------------------------------------------------------
  99.  
  100. FW_CPrivNameToLabelMap& FW_CPrivArchiver::GetNameToLabelMap()
  101. {
  102.     return *GetArchiverGlobals().gNameToLabelMap;
  103. }
  104.  
  105. //----------------------------------------------------------------------------------------
  106. // FW_CArchiveDictionary& FW_CPrivArchiver::GetLabelToIOFunctionMap
  107. //----------------------------------------------------------------------------------------
  108.  
  109. FW_CPrivLabelToIOFunctionMap& FW_CPrivArchiver::GetLabelToIOFunctionMap()
  110. {
  111.     return *GetArchiverGlobals().gLabelToIOFunctionMap;
  112. }
  113.  
  114. //----------------------------------------------------------------------------------------
  115. // FW_CPrivArchiver::GetArchiverGlobals
  116. //----------------------------------------------------------------------------------------
  117.  
  118. FW_SPrivArchiverGlobals& FW_CPrivArchiver::GetArchiverGlobals()
  119. {
  120.     FW_SPrivArchiverGlobals *globals = &gGlobals;
  121.  
  122.     if (globals->gNameToLabelMap == 0)
  123.         Initialize(*globals);
  124.     return *globals;
  125. }
  126.  
  127. //----------------------------------------------------------------------------------------
  128. // FW_CPrivArchiver::AddNameToLabelPair
  129. //----------------------------------------------------------------------------------------
  130.  
  131. void FW_CPrivArchiver::AddNameToLabelPair(FW_ClassTypeConstant classLabel, const char* className)
  132. {
  133. #ifdef FW_DEBUG
  134.     FW_ASSERT(("Can't register a class as archivable if it doesn't have RTTI.", className != 0));
  135.     FW_CPrivNameToLabelPair* pair = GetNameToLabelMap().Find(FW_SPrivArcStr(className));
  136.     if (pair !=0)
  137.     {
  138.         char buffer[256];
  139.         sprintf(buffer, "Class %s has already been registered as archivable!", className);
  140.         FW_DEBUG_MESSAGE(buffer);
  141.     }
  142. #endif
  143.  
  144.     GetNameToLabelMap()[FW_SPrivArcStr(className)] = classLabel;
  145. }
  146.  
  147. //----------------------------------------------------------------------------------------
  148. // FW_CPrivArchiver::AddLabelToIOFunctionPair
  149. //----------------------------------------------------------------------------------------
  150.  
  151. void FW_CPrivArchiver::AddLabelToIOFunctionPair(FW_ClassTypeConstant classLabel, const FW_SPrivArcFun& functions)
  152. {
  153. #ifdef FW_DEBUG
  154.     FW_ASSERT(GetLabelToIOFunctionMap().Find(classLabel) == 0);
  155. #endif
  156.  
  157.     GetLabelToIOFunctionMap()[classLabel] = functions;
  158. }
  159.  
  160. //----------------------------------------------------------------------------------------
  161. // FW_CPrivArchiver::FW_CPrivArchiver
  162. //----------------------------------------------------------------------------------------
  163.  
  164. FW_CPrivArchiver::FW_CPrivArchiver(FW_ClassTypeConstant classLabel,
  165.                                 const char* className,
  166.                                 const FW_SPrivArcFun& functions)
  167. {
  168.     AddNameToLabelPair(classLabel, className);
  169.     AddLabelToIOFunctionPair(classLabel, functions);
  170. }
  171.  
  172. //----------------------------------------------------------------------------------------
  173. // FW_CPrivArchiver::FW_CPrivArchiver
  174. //----------------------------------------------------------------------------------------
  175.  
  176. FW_CPrivArchiver::FW_CPrivArchiver(FW_ClassTypeConstant classLabel,
  177.                                 const FW_SPrivArcFun& functions)
  178. {
  179.     AddLabelToIOFunctionPair(classLabel, functions);
  180. }
  181.  
  182. //----------------------------------------------------------------------------------------
  183. // FW_CPrivArchiver::PreregisterSpecialObject
  184. //----------------------------------------------------------------------------------------
  185.  
  186. void FW_CPrivArchiver::PreregisterSpecialObject(
  187.                                     FW_CReadableStream& readableStream,
  188.                                     const void* object,
  189.                                     FW_ObjectRegistry_ID objectID)
  190. {
  191.     FW_SOMEnvironment ev;
  192.     FW_OObjectRegistry* registry = readableStream.GetRegistry();
  193.     registry->RegisterObjectAndID(ev, (void*) object, objectID);
  194. }
  195.  
  196. //----------------------------------------------------------------------------------------
  197. // ClassLabel_Create
  198. //
  199. // Notes:
  200. //    1.    You may have expected this method to return a pointer to the class label. Doing
  201. //        so, however, would result in two problems. First, the pointer returned would have
  202. //        to be to a buffer allocated by this method and who would delete it? Second, even
  203. //        if a pointer to a class label was returned, by returning a FW_SPrivArcFun
  204. //        pointer, we only have to map a particular class label once (via the map
  205. //        'gLabelToIOFunctionMap') for the entire 'readableStream'. That is,
  206. //        if there are "n" occurrences of a particular class label in a 'readableStream',
  207. //        one reference to 'gLabelToIOFunctionMap' is made instead of "n".
  208. //----------------------------------------------------------------------------------------
  209.  
  210. static void* ClassLabel_Create(FW_CReadableStream& stream, FW_ClassTypeConstant type)
  211. {
  212. FW_UNUSED(type);
  213.     // Read the class label of the object from the archive.
  214.     FW_ClassTypeConstant label;
  215.     stream >> label;
  216.     FW_CPrivLabelToIOFunctionPair* pair = FW_CPrivArchiver::LookupArchivingFunctions(label);
  217.     if (pair == NULL)
  218.     {
  219.         // If you get this assertion there is a good chance that it's because you loaded
  220.         // views from resources and forgot to use the macro FW_DO_NOT_DEAD_STRIP in your
  221.         // code for those classes that are not referenced anywhere else, for instance 
  222.         // FW_DO_NOT_DEAD_STRIP(FW_CGrowBox).   See the ODF samples.
  223. #ifdef FW_DEBUG
  224.         char msg[255];
  225.         sprintf(msg, "'%4s' class not registered for archiving. Forgot FW_DO_NOT_DEAD_STRIP ?", (char *)&label);
  226.         FW_DEBUG_MESSAGE(msg);
  227. #endif
  228.     }
  229.     return pair;
  230. }
  231.  
  232. //----------------------------------------------------------------------------------------
  233. // ClassLabel_Output
  234. //----------------------------------------------------------------------------------------
  235.  
  236. static void ClassLabel_Output(FW_CWritableStream& stream, FW_ClassTypeConstant type, const void *object)
  237. {
  238. FW_UNUSED(type);
  239.     FW_CPrivLabelToIOFunctionPair* item = (FW_CPrivLabelToIOFunctionPair*) object;
  240.     FW_ClassTypeConstant label = item->fKey;
  241.     stream << label;
  242. }
  243.  
  244. //----------------------------------------------------------------------------------------
  245. // FW_CPrivArchiver::LookupArchivingFunctions
  246. //----------------------------------------------------------------------------------------
  247.  
  248. FW_CPrivLabelToIOFunctionPair* FW_CPrivArchiver::LookupArchivingFunctions(FW_ClassTypeConstant label)
  249. {
  250.     static FW_CPrivLabelToIOFunctionPair* gCachedMetaPair = GetLabelToIOFunctionMap().Find(kMetaClassTypeConstant);
  251.     FW_CPrivLabelToIOFunctionPair* result = 0;
  252.     if (kMetaClassTypeConstant == label)
  253.         result = gCachedMetaPair;
  254.     else
  255.         result = GetLabelToIOFunctionMap().Find(label);
  256.     return result;
  257. }
  258.  
  259. //----------------------------------------------------------------------------------------
  260. // FW_CPrivArchiver::CreateObject
  261. //----------------------------------------------------------------------------------------
  262.  
  263. void FW_CPrivArchiver::CreateObject(FW_CReadableStream& readableStream, void*& object)
  264. {
  265.     FW_CPrivLabelToIOFunctionPair* pair = (FW_CPrivLabelToIOFunctionPair*) 
  266.         PrivCreateObject(readableStream, kMetaClassTypeConstant);
  267.     object = PrivCreateObject(readableStream, pair ? pair->fKey : FW_kNullTypeConstant);
  268. }
  269.  
  270. //----------------------------------------------------------------------------------------
  271. // FW_CPrivArchiver::OutputObject
  272. //----------------------------------------------------------------------------------------
  273.  
  274. void FW_CPrivArchiver::OutputObject(FW_CWritableStream& writableStream,
  275.                                        const void* object,
  276.                                        const char* className)
  277. {
  278.     if (!object)
  279.     {
  280.         writableStream << kIDOnly << kNULLObjectID;    // Null class
  281.         writableStream << kIDOnly << kNULLObjectID;    // Null object
  282.     }
  283.     else
  284.     {
  285.         FW_SPrivArcStr tempName(className);
  286.         FW_ASSERT(GetNameToLabelMap().Find(tempName));
  287.         FW_ClassTypeConstant label = GetNameToLabelMap()[tempName];
  288.     
  289.         FW_CPrivLabelToIOFunctionPair* item = GetLabelToIOFunctionMap().Find(label);
  290.         FW_ASSERT(item);
  291.     
  292.         // Write the class label out to the archive.
  293.         PrivOutputObject(writableStream, kMetaClassTypeConstant, item);
  294.  
  295.         // Write the 'object' data out to the archive.
  296.         PrivOutputObject(writableStream, label, object);
  297.     }
  298. }
  299.  
  300. //----------------------------------------------------------------------------------------
  301. // FW_CPrivArchiver::Initialize
  302. //----------------------------------------------------------------------------------------
  303.  
  304. void FW_CPrivArchiver::Initialize(FW_SPrivArchiverGlobals& globals)
  305. {
  306.     globals.gNameToLabelMap = 
  307.             new FW_CPrivNameToLabelMap(FW_PrivCompareNames);
  308.     globals.gLabelToIOFunctionMap = 
  309.             new FW_CPrivLabelToIOFunctionMap(FW_PrivCompareLabels);
  310. }
  311.  
  312. //----------------------------------------------------------------------------------------
  313. // FW_CPrivArchiver::Terminate
  314. //----------------------------------------------------------------------------------------
  315.  
  316. void FW_CPrivArchiver::Terminate()
  317. {
  318.     FW_SPrivArchiverGlobals& globals = GetArchiverGlobals();
  319.     delete globals.gNameToLabelMap;
  320.     delete globals.gLabelToIOFunctionMap;
  321. }
  322.  
  323. //========================================================================================
  324. //    Struct FW_SPrivArcStr
  325. //========================================================================================
  326.  
  327. //----------------------------------------------------------------------------------------
  328. // FW_SPrivArcStr::FW_SPrivArcStr
  329. //----------------------------------------------------------------------------------------
  330.  
  331. FW_SPrivArcStr::FW_SPrivArcStr(const char* string) :
  332.     fString(string)
  333. {
  334.     FW_ASSERT(this->fString != NULL);
  335. }
  336.  
  337. //========================================================================================
  338. //    Struct FW_SPrivArcFun
  339. //========================================================================================
  340.  
  341. //----------------------------------------------------------------------------------------
  342. // FW_SPrivArcFun::FW_SPrivArcFun
  343. //----------------------------------------------------------------------------------------
  344.  
  345. FW_SPrivArcFun::FW_SPrivArcFun(Create create,
  346.                                 Initialize initialize,
  347.                                 Destroy destroy,
  348.                                 Output output) :
  349.     fCreateFunction(create),
  350.     fInitializeFunction(initialize),
  351.     fDestroyFunction(destroy),
  352.     fOutputFunction(output)
  353. {
  354. #ifdef FW_DEBUG
  355.     if (fInitializeFunction != NULL)
  356.         FW_ASSERT(("If an initialize function is registered, a destroy function must be too", fDestroyFunction != NULL));
  357. #endif
  358. }
  359.  
  360. //========================================================================================
  361. //    Keys Matching Function
  362. //========================================================================================
  363.  
  364. //----------------------------------------------------------------------------------------
  365. //    FW_PrivKeysMatchProc
  366. //----------------------------------------------------------------------------------------
  367.  
  368. int FW_PrivCompareNames(void* k1, void* k2)
  369. {
  370.     FW_CPrivNameToLabelPair* key1 = (FW_CPrivNameToLabelPair*) k1;
  371.     FW_CPrivNameToLabelPair* key2 = (FW_CPrivNameToLabelPair*) k2;
  372.     return FW_PrimitiveStringCompare(key1->fKey.fString, key2->fKey.fString);
  373. }
  374.  
  375. int FW_PrivCompareLabels(void* k1, void* k2)
  376. {
  377.     FW_CPrivLabelToIOFunctionPair* key1 = (FW_CPrivLabelToIOFunctionPair*) k1;
  378.     FW_CPrivLabelToIOFunctionPair* key2 = (FW_CPrivLabelToIOFunctionPair*) k2;
  379.     if (key1->fKey < key2->fKey)
  380.         return -1;
  381.     else if (key1->fKey == key2->fKey)
  382.         return 0;
  383.     else
  384.         return 1;
  385. }
  386.  
  387. //----------------------------------------------------------------------------------------
  388. // FW_CPrivArchiver::PrivCreateObject
  389. //----------------------------------------------------------------------------------------
  390.  
  391. void* FW_CPrivArchiver::PrivCreateObject(FW_CReadableStream& readableStream, 
  392.                                         FW_ClassTypeConstant classLabel)
  393. {
  394.     FW_SOMEnvironment ev;
  395.     void* objectPtr = NULL;
  396.     FW_OObjectRegistry* registry = readableStream.GetRegistry();
  397.  
  398.     short byValue;
  399.     FW_ObjectRegistry_ID id;
  400.  
  401.     readableStream >> byValue >> id;
  402.  
  403.     switch (byValue)
  404.     {
  405.         case kIDOnly:
  406.         {
  407.             if (id == FW_kPrivNULLObjectID)
  408.                 objectPtr = NULL;
  409.             else
  410.             {
  411.                 objectPtr = registry->LookupByID(ev, id);
  412.                 FW_ASSERT(("Object registry ID was not found in registry", objectPtr != NULL));
  413.                 // If the above assertion fails, the stream is probably corrupt.
  414.                 // However, one should check to see (using a debugger) if the id is a negative
  415.                 // value.  If so, then the stream may have a reference to a preregistered object,
  416.                 // but for some reason the object wasn't preregistered at runtime.
  417.                 if (objectPtr == NULL)
  418.                     FW_Failure(FW_xCorruptArchiveStream);
  419.             }
  420.             break;
  421.         }
  422.         case kIDAndValue:
  423.         {
  424.             // We allow for two-step construction here.
  425.             // 1) Allocate raw memory and possibly do minimal initialization
  426.             // 2) Finish full initialization
  427.             // Object is registered between steps 1 and 2. Object objects
  428.             // created during step 2 can have references back to this object.
  429.             FW_CPrivLabelToIOFunctionPair* pair = LookupArchivingFunctions(classLabel);
  430.             if (pair == NULL)
  431.                 pair = LookupArchivingFunctions(FW_kWildCardLabel);
  432.             FW_ASSERT(("No registered archiving functions for class label", pair != NULL));
  433.             if (pair == NULL)
  434.                 FW_Failure(FW_xCorruptArchiveStream);
  435.  
  436.             FW_SPrivArcFun* archivingFunctions = &pair->fValue;
  437.             FW_SPrivArcFun::Create create = archivingFunctions->fCreateFunction;
  438.             FW_ASSERT(("Attempt to create object from stream with NULL create function", create != NULL));
  439.             if (create == NULL)
  440.                 FW_Failure(FW_xCorruptArchiveStream);
  441.             
  442.             objectPtr = create(readableStream, classLabel);
  443.             FW_ASSERT(objectPtr != NULL);
  444.             if (objectPtr == NULL)
  445.                 FW_Failure(FW_xCorruptArchiveStream);
  446.  
  447.             if (id != kNotInRegistry)
  448.                 registry->RegisterObjectAndID(ev, objectPtr, id);
  449.  
  450.             FW_SPrivArcFun::Initialize initialize = archivingFunctions->fInitializeFunction;
  451.             if (initialize != 0)
  452.             {
  453.                 FW_SPrivArcFun::Destroy destroy = archivingFunctions->fDestroyFunction;
  454.                 FW_ASSERT(destroy != NULL);
  455.                 if (destroy == NULL)
  456.                     FW_Failure(FW_xCorruptArchiveStream);
  457.                 FW_TRY
  458.                 {
  459.                     initialize(readableStream, classLabel, objectPtr);
  460.                 }
  461.                 FW_CATCH_BEGIN
  462.                 FW_CATCH_EVERYTHING()
  463.                 {
  464.                     destroy(objectPtr, classLabel);
  465.                     FW_THROW_SAME();
  466.                 }
  467.                 FW_CATCH_END
  468.             }
  469.             break;
  470.         }
  471.         default:
  472.         {
  473.             FW_ASSERT(false);
  474.             FW_Failure(FW_xCorruptArchiveStream);
  475.             break;
  476.         }
  477.     }
  478.  
  479.     return objectPtr;
  480. }
  481.  
  482. //----------------------------------------------------------------------------------------
  483. // FW_CPrivArchiver::PrivOutputObject
  484. //----------------------------------------------------------------------------------------
  485.  
  486. void FW_CPrivArchiver::PrivOutputObject(FW_CWritableStream& writableStream, 
  487.                                         FW_ClassTypeConstant classLabel,
  488.                                         const void* object)
  489. {
  490.     FW_SOMEnvironment ev;
  491.  
  492.     FW_OObjectRegistry* registry = writableStream.GetRegistry();
  493.     FW_ObjectRegistry_ID id = registry->LookupByObject(ev, (void*) object);
  494.  
  495.     if (id == kNotInRegistry)
  496.     {
  497.         FW_CPrivLabelToIOFunctionPair* pair = LookupArchivingFunctions(classLabel);
  498.         if (pair == NULL)
  499.             pair = LookupArchivingFunctions(FW_kWildCardLabel);
  500.         FW_ASSERT(("No registered archiving functions for class label", pair != NULL));
  501.         if (pair == NULL)
  502.             FW_Failure(FW_xCorruptArchiveStream);
  503.     
  504.         FW_SPrivArcFun* archivingFunctions = &pair->fValue;
  505.         FW_SPrivArcFun::Output output = archivingFunctions->fOutputFunction;
  506.         FW_ASSERT(output != NULL);
  507.         if (output == NULL)
  508.             FW_Failure(FW_xCorruptArchiveStream);
  509.     
  510.         id = registry->RegisterObject(ev, (void*) object);
  511.         writableStream << kIDAndValue << id;
  512.         output(writableStream, classLabel, object);
  513.     }
  514.     else
  515.     {
  516.         writableStream << kIDOnly << id;
  517.     }
  518. }
  519.